﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NPOI.SS.UserModel;
using Vowei.Core.Models;
using System.Globalization;
using System.Diagnostics;
using NPOI.HSSF.UserModel;
using System.Text.RegularExpressions;
using Vowei.Data;
using System.IO;
using Vowei.Data.Converters.Excel;
using Vowei.Data.Helpers;
using Vowei.Data.Models;

namespace Vowei.Converters.Helpers
{
    public static class ConverterHelpers
    {
        public static CultureInfo CurrentCulture { get { return CultureInfo.CurrentUICulture; } }

        public static void CreateDateCell(this Row row, int cellNum, DateTime? value)
        {
            CreateDateCell(row, cellNum, value, CurrentCulture);
        }

        public static void CreateDateCell(this Row row, int cellNum, DateTime? value, CultureInfo culture)
        {
            if (row == null)
                throw new NullReferenceException();
            if (cellNum < 0)
                throw new ArgumentOutOfRangeException("cellNum");

            var cell = row.CreateCell(cellNum);
            SetCellDateTimeFormat(cell, culture);
            if (value.HasValue) cell.SetCellValue(value.Value.ToOADate());
        }

        public static void SetCellDateTimeFormat(this Cell cell, CultureInfo culture)
        {
            var row = cell.Row;
            var format = row.Sheet.Workbook.CreateDataFormat();
            cell.CellStyle = row.Sheet.Workbook.CreateCellStyle();
            // TODO: 下面这个要考虑到时间的格式
            cell.CellStyle.DataFormat = format.GetFormat(culture.DateTimeFormat.LongDatePattern);
        }

        public static void SetCellDateTimeValue(this Cell cell, DateTime value)
        {
            SetCellDateTimeValue(cell, value, CurrentCulture);
        }

        public static void SetCellDateTimeValue(this Cell cell, DateTime value, CultureInfo culture)
        {
            SetCellDateTimeFormat(cell, culture);            
            cell.SetCellValue(value);
        }

        public static void CopyTo(this Row source, Row target)
        {
            if (source == null)
                throw new NullReferenceException();
            if (target == null)
                throw new ArgumentNullException("another");

            if (source.RowStyle != null)
            {
                target.RowStyle = target.Sheet.Workbook.CreateCellStyle();
                target.RowStyle.CloneStyleFrom(source.RowStyle);
            }

            for (var i = source.FirstCellNum; i < source.LastCellNum; ++i)
            {
                var cell = (HSSFCell)source.GetCell(i);
                var newCell = (HSSFCell)target.CreateCell(i);

                cell.CopyTo(newCell);
            }
        }

        public static void CopyTo(this HSSFCell source, HSSFCell target)
        {
            if (source == null)
                throw new NullReferenceException();
            if (target == null)
                throw new ArgumentNullException("another");

            if (source.CellStyle != null)
            {
                target.CellStyle = target.Sheet.Workbook.CreateCellStyle();
                target.CellStyle.CloneStyleFrom(source.CellStyle);
            }
            target.SetCellType(source.CellType);

            CopyCellValue(source, target, source.CellType);
        }

        private static TableEqualityComparer _comparer = new TableEqualityComparer();
        public static void ConvertToExcel(
            this Project project, IVoweiContext context, Stream stream, string excelTmplPath)
        {
            if (project == null)
                throw new NullReferenceException();
            if (context == null)
                throw new ArgumentNullException("context");
            if (stream == null)
                throw new ArgumentNullException("stream");
            if (string.IsNullOrEmpty(excelTmplPath))
                throw new ArgumentNullException("excelTmplPath");

            var target = new WorkItemExcelConverter(context.TicketStatusManager);
            target.TemplateExcel = excelTmplPath;
            var works = new List<ITable>();
            works.Add(project);
            // TODO: remove below comment after test TicketBelongsToMilestoneForeignKeyTest is passed
            // works.AddRange(context.Requirements.Query.Where(r => r.BelongsToMilestone.ID == project.ID));
            works.AddRange(context.Requirements.Query.Where(r => r.BelongsToMilestoneId == project.ID));

            foreach (var milestone in project.Children.OrderBy(m => m.StartDate))
            {
                works.Add(milestone);
                works.AddRange(milestone.AllRequirements(context));
            }

            target.ConvertTo(works.Distinct(_comparer), stream);
        }

        private static Regex _cellRefRegex = new Regex(@"(\$?[A-Z]+)(\$?\d+)", RegexOptions.IgnoreCase);
        private static void CopyCellValue(HSSFCell source, HSSFCell target, CellType type)
        {
            switch (type)
            {
                case CellType.BOOLEAN:
                    target.SetCellValue(source.BooleanCellValue);
                    break;

                case CellType.ERROR:
                    target.SetCellErrorValue(source.CellErrorValue);
                    break;

                case CellType.NUMERIC:
                    target.SetCellValue(source.NumericCellValue);
                    break;

                case CellType.STRING:
                    target.SetCellValue(source.StringCellValue);
                    break;

                case CellType.FORMULA:
                    var mythPrefix = "_xlfn.";
                    string formula = null;
                    if ( source.CellFormula.StartsWith(mythPrefix) )
                        formula = source.CellFormula.Substring(mythPrefix.Length);
                    else
                        formula = source.CellFormula;

                    // TODO: 这里是潜在的性能瓶颈
                    formula = _cellRefRegex.Replace(
                        formula,
                        m => string.Format("{0}{1}", m.Groups[1], target.RowIndex + 1));
                    target.CellFormula = formula;
                    break;

                default:
                    Trace.WriteLine(string.Format("不支持的单元格类型： {0}", type));
                    break;
            }
        }
    }
}
